define([
    'dojo/_base/declare',
    'dojo/_base/connect',
    'dojo/_base/array',
    'dojo/dom-construct',
    'dojo/dom-style',
    'dojo/number',
    'esri/lang',
    'esri/domUtils',
    'esri/SpatialReference',
    'esri/geometry/Point',
    'esri/layers/layer',
    'geomap/plugins/layers/RasterLayer',
    'geomap/plugins/Windy',
], function (
    declare,
    connect,
    arrayUtils,
    domConstruct,
    domStyle,
    number,
    esriLang,
    domUtils,
    SpatialReference,
    Point,
    Layer,
    RasterLayer,
    Windy
) {
    var _this = null;
    var RL = declare([RasterLayer], {
        // Doc: http://docs.dojocampus.org/dojo/declare#chaining
        '-chains-': {
            constructor: 'manual',
        },
        constructor: function (options) {
            // Manually call superclass constructor with required arguments
            this.inherited(arguments, ['http://some.server.com/path', options]);
            _this = this;
            this.options = Object.assign({ projection: 'EPSG:4326' }, options);
            this.loaded = true;
            this.isClear = false;
            this.onLoad(this);
        },
        _setMap: function (map, container) {
            this._map = map;
            _this.map = map;
            var element = (this._canvas = domConstruct.create(
                'canvas',
                {
                    id: 'canvas',
                    width: map.width + 'px',
                    height: map.height + 'px',
                    style: 'position: absolute; left: 0px; top: 0px;',
                },
                container
            ));

            if (esriLang.isDefined(this.opacity)) {
                domStyle.set(element, 'opacity', this.opacity);
            }

            this._context = element.getContext('2d');
            if (!this._context) {
                console.error('This browser does not support <canvas> elements.');
            }

            this._mapWidth = map.width;
            this._mapHeight = map.height;

            // Event connections
            this._connects = [];
            this._connects.push(
                connect.connect(map, 'onPanStart', this, () => {
                    element.style.display = 'none';
                })
            );
            this._connects.push(connect.connect(map, 'onPanEnd', this, this.redraw));
            this._connects.push(
                connect.connect(map, 'onZoomStart', this, () => {
                    element.style.display = 'none';
                })
            );
            this._connects.push(connect.connect(map, 'onZoomEnd', this, this.redraw));
            this._connects.push(connect.connect(map, 'onExtentChange', this, this.redraw));
            this._connects.push(connect.connect(this, 'onVisibilityChange', this, this.redraw));
            this._connects.push(connect.connect(map, 'onClick', this, this._onClickHandler));
            this._connects.push(
                connect.connect(map, 'onMouseMove', this, this._onMouseMoveHandler)
            );

            return element;
        },
        _unsetMap: function (map, container) {
            arrayUtils.forEach(this._connects, connect.disconnect, this);
            if (this._canvas) {
                container.removeChild(this._canvas);
            }
            this._map = this._canvas = this._context = this.data = this._connects = null;
        },
        _elementVisible: true,
        allgrid: [],
        _windyIdentifyLayerName: 'windyPt',
        _calDetailInfo(evt) {
            var me = this;
            var mapUtils = me.mapUtils;
            mapUtils._currentClickLayer = me.id;

            var point = evt.mapPoint;
            point.lng =
                (evt.mapPoint.getLongitude && evt.mapPoint.getLongitude()) || evt.mapPoint.x;
            point.lat = (evt.mapPoint.getLatitude && evt.mapPoint.getLatitude()) || evt.mapPoint.y;
            if (!me.$Wind) {
                return;
            }
            var gridValue = me.$Wind.interpolatePoint(point.lng, point.lat);
            var result = {};

            if (gridValue && !isNaN(gridValue[0]) && !isNaN(gridValue[1])) {
                var uMs = gridValue[0];
                var vMs = gridValue[1];
                vMs = vMs > 0 ? (vMs = vMs - vMs * 2) : Math.abs(vMs);
                var temp = gridValue[2];

                result.angle = mapUtils.getWindyAngle(uMs, vMs);
                result.direction = mapUtils.getWindyDirection(result.angle);
                result.speed = mapUtils.getWindySpeed(uMs, vMs).toFixed(1);
                result.speedUtil = 'm/s';
                result.temp = '--';
                result.tempUtil = '';
                if (!isNaN(temp)) {
                    //result.temp = (temp - 273.15).toFixed(1);
                    result.temp = temp.toFixed(1);
                    result.tempUtil = '°C';
                }
                result.level = mapUtils.getWindyLevel(result.speed);
                result.levelUtil = '级';
            }
            var data = Object.assign({ x: point.x, y: point.y }, result);

            evt.graphic = {
                attributes: data,
                geometry: point,
            };
            me._event = evt;
            var e = {
                mapView: me.mapView,
                data: data,
                getLocation: me.getLocation.bind(me),
            };
            return e;
        },
        _onMouseMoveHandler(evt) {
            var me = this;
            if (Object.prototype.toString.call(me.mouseMoveEvt) == '[object Function]') {
                var e = me._calDetailInfo(evt);
                me.mouseMoveEvt(e);
            }
        },
        _onClickHandler(evt) {
            var me = this;

            if (Object.prototype.toString.call(this.clickEvt) == '[object Function]') {
                var e = me._calDetailInfo(evt);
                me.clickEvt(e);
            }
        },
        getLocation: function () {
            var esriEvent = this._event;
            var location = this.getGraphicLocation(this.mapView, esriEvent);
            location.event = esriEvent;
            return location;
        },
        getGraphicLocation: function (mapView, esriEvent) {
            if (!esriEvent || !esriEvent.graphic) {
                return;
            }
            if (!mapView) {
                return;
            }
            var map = mapView.getMap();
            if (!map) {
                return;
            }
            var geometry = esriEvent.graphic.geometry || {};
            var lngFieldName = mapView.getLngFieldName();
            var latFieldName = mapView.getLatFieldName();
            var location = {};
            location[lngFieldName] = geometry.x;
            location[latFieldName] = geometry.y;
            return location;
        },
        refresh: function () {
            if (!this._canDraw()) {
                return;
            }
        },
        clear: function () {
            if (!this._canDraw()) {
                return;
            }

            this._context.clearRect(0, 0, this._mapWidth, this._mapHeight);
        },
        _canDraw: function () {
            return this._map && this._canvas && this._context ? true : false;
        },
        _panHandler: function (extent, delta) {
            domStyle.set(this._canvas, { left: delta.x + 'px', top: delta.y + 'px' });
        },
        _extentChangeHandler: function (extent, delta, levelChange, lod) {
            if (!levelChange) {
                domStyle.set(this._canvas, { left: '0px', top: '0px' });
                this.clear();
            }
        },
        _visibilityChangeHandler: function (visible) {
            if (visible) {
                domUtils.show(this._canvas);
            } else {
                domUtils.hide(this._canvas);
            }
        },
        hide: function (e) {
            this.inherited(arguments);
            domUtils.hide(this._canvas);
        },
        show: function (e) {
            this.inherited(arguments);
            domUtils.show(this._canvas);
        },
        render: function () {
            const extent = this._getExtent();
            if (this._canvas && !this.$Wind) {
                this.$Wind = new Windy({
                    canvas: this._canvas,
                    data: this.data,
                    projection: this.options.projection,
                    windColors: this.options.windColors,
                    particleScale: this.options.particleScale,
                });

                this.$Wind.start(extent[0], extent[1], extent[2], extent[3]);
            } else if (this._canvas && this.$Wind) {
                this.$Wind.start(extent[0], extent[1], extent[2], extent[3]);
            }
            if (!this.visible) {
                return;
            }
            this.setScale(this.map, this._canvas);
        },
        _getExtent: function () {
            var extent = _this.map.geographicExtent || _this.map.extent;

            return [
                [
                    [0, 0],
                    [_this.map.width, _this.map.height],
                ],
                _this.map.width,
                _this.map.height,
                [
                    [extent.xmin, extent.ymin],
                    [extent.xmax, extent.ymax],
                ],
            ];
        },
        redraw() {
            if (!_this.$Wind) {
                return;
            }
            _this.$Wind.stop();
            if (!this.visible) {
                return;
            }
            this.setScale(this.map, _this._canvas);
            if (!this._elementVisible) {
                return;
            }
            _this._canvas.width = _this.map.width;
            _this._canvas.height = _this.map.height;
            const extent = _this._getExtent();
            setTimeout(function () {
                _this.$Wind.start(extent[0], extent[1], extent[2], extent[3]);
            });
        },
        getData: function () {
            return this.data;
        },
        setData: function (mapView, layer) {
            var me = this;
            const _map = this.getMap();
            if (!_map) return this;
            var options = layer.layer || {};

            me.mapView = mapView;
            var mapUtils = mapView.mapUtils;
            me.mapUtils = mapUtils;
            me.clickEvt = options.onClick;
            me.mouseMoveEvt = options.onMouseMove;
            this.options.minScale = options.minScale;
            this.options.maxScale = options.maxScale;
            debugger;
            this.options.particleScale =
                options.particleScale || (options.options && options.options.particleScale);
            var data = options.data || [];
            this.data = data;
            this.isClear = false;
            if (options.url) {
                $.ajax({
                    url: options.url,
                    success: function (res) {
                        me.data = res;
                        if (me._canvas) {
                            renderWind.bind(me)(me.data);
                        }
                    },
                });
            } else {
                if (me._canvas) {
                    renderWind.bind(me)(data);
                }
            }
            function renderWind(data) {
                if (!me.$Wind) {
                    me.render(me._canvas);
                } else if (me.$Wind) {
                    const extent = me._getExtent();
                    me.$Wind.update(me.getData(), extent[0], extent[1], extent[2], extent[3]);
                }
            }

            return this;
        },
        getMap: function () {
            return _this.map;
        },
        clearWind() {
            const _map = _this.getMap();
            if (!_map) return;
            if (this.$Wind) this.$Wind.stop();
            this.isClear = true;
            this._cloneLayer = this;
            _map.removeLayer(this);
        },
        removeLayer: function () {
            const _map = _this.getMap();
            if (!_map) return;
            if (_this.$Wind) _this.$Wind.stop();
            if (_this._connects && _this._connects.length > 0) {
                _this._connects.map(function (item) {
                    item.remove();
                    item = null;
                });
            }
            _map.removeLayer(this);
            delete this._canvas;
            delete this.$Wind;
            delete this._cloneLayer;
        },
    });

    return RL;
});
